// ------------------------------------------------------------
// Copyright (c) Microsoft Corporation.  All rights reserved.
// Licensed under the MIT License (MIT). See License.txt in the repo root for license information.
// ------------------------------------------------------------

#include "stdafx.h"

using namespace Api;
using namespace Common;

#if !defined(PLATFORM_UNIX)
BOOL APIENTRY DllMain(
    HMODULE module,
    DWORD reason,
    LPVOID reserved)
{
    UNREFERENCED_PARAMETER(module);
    UNREFERENCED_PARAMETER(reserved);

    switch (reason)
    {
    case DLL_PROCESS_ATTACH:
    case DLL_THREAD_ATTACH:
    case DLL_THREAD_DETACH:
    case DLL_PROCESS_DETACH:
        break;
    }
    return TRUE;
}
#endif

//
// WARNING: 
//
// The signature below MUST exactly match (including the parameter names)
// with the signature generated by MIDL in the header file.
// Otherwise the linker does not apply the extern "C" specifier and exports 
// this function as C++ name mangled function instead of C style function.

/* [entry] */ HRESULT FabricCreateNativeImageStoreClient( 
	/* [in] */ BOOLEAN isInternal,
    /* [in] */ LPCWSTR workingDirectory,    
    /* [in] */ USHORT connectionStringsSize,
    /* [size_is][in] */ __RPC__in_ecount_full(connectionStringsSize) const LPCWSTR *connectionStrings,
    /* [in] */ __RPC__in REFIID riid,
    /* [retval][out] */ __RPC__deref_out_opt void **nativeImageStoreClient)
{
    Common::DllConfig::GetConfig();

    Api::IClientFactoryPtr factoryPtr;
    auto error = Client::ClientFactory::CreateClientFactory(
        connectionStringsSize,
        connectionStrings,
        factoryPtr);

    if (!error.IsSuccess()) { return Common::ComUtility::OnPublicApiReturn(error.ToHResult()); }

    std::wstring dir;
    auto hr = Common::StringUtility::LpcwstrToWstring(workingDirectory, true, dir);
    if (FAILED(hr)) { return Common::ComUtility::OnPublicApiReturn(hr); }
    
    Api::INativeImageStoreClientPtr implPtr;
    error = Management::ImageStore::NativeImageStore::CreateNativeImageStoreClient(
		isInternal == TRUE,
        dir,         
        factoryPtr,
        implPtr);

    if (!error.IsSuccess()) { return Common::ComUtility::OnPublicApiReturn(error.ToHResult()); }

    Common::ComPointer<IFabricNativeImageStoreClient> comPtr = Api::ComNativeImageStoreClient::CreateComNativeImageStoreClient(implPtr);

    hr = comPtr->QueryInterface(riid, nativeImageStoreClient);

    return Common::ComUtility::OnPublicApiReturn(hr);
}

/* [entry] */ HRESULT FabricCreateLocalNativeImageStoreClient( 
	/* [in] */ BOOLEAN isInternal,
    /* [in] */ LPCWSTR workingDirectory,    
    /* [in] */ __RPC__in REFIID riid,
    /* [retval][out] */ __RPC__deref_out_opt void **nativeImageStoreClient)
{
    Common::DllConfig::GetConfig();

    Api::IClientFactoryPtr factoryPtr;
    auto error = Client::ClientFactory::CreateLocalClientFactory(
        std::make_shared<FabricNodeConfig>(),
        factoryPtr);

    if (!error.IsSuccess()) { return Common::ComUtility::OnPublicApiReturn(error.ToHResult()); }

    std::wstring dir;
    auto hr = Common::StringUtility::LpcwstrToWstring(workingDirectory, true, dir);
    if (FAILED(hr)) { return Common::ComUtility::OnPublicApiReturn(hr); }

    Api::INativeImageStoreClientPtr implPtr;
    error = Management::ImageStore::NativeImageStore::CreateNativeImageStoreClient(
		isInternal == TRUE,
        dir, 
        factoryPtr,
        implPtr);

    if (!error.IsSuccess()) { return Common::ComUtility::OnPublicApiReturn(error.ToHResult()); }

    Common::ComPointer<IFabricNativeImageStoreClient> comPtr = Api::ComNativeImageStoreClient::CreateComNativeImageStoreClient(implPtr);

    hr = comPtr->QueryInterface(riid, nativeImageStoreClient);

    return Common::ComUtility::OnPublicApiReturn(hr);
}

HRESULT ArchiveApplicationPackage(
    LPCWSTR appPackageRootDirectory,
    IFabricNativeImageStoreProgressEventHandler const * progressHandler)
{
    std::wstring dir;
    auto hr = Common::StringUtility::LpcwstrToWstring(appPackageRootDirectory, false, dir);
    if (FAILED(hr)) { return Common::ComUtility::OnPublicApiReturn(hr); }

    hr = Management::ImageStore::ImageStoreUtility::ArchiveApplicationPackage(
        dir,
        WrapperFactory::create_rooted_com_proxy(const_cast<IFabricNativeImageStoreProgressEventHandler*>(progressHandler))).ToHResult();
    return Common::ComUtility::OnPublicApiReturn(hr);
}

HRESULT TryExtractApplicationPackage(
    LPCWSTR appPackageRootDirectory, 
    IFabricNativeImageStoreProgressEventHandler const * progressHandler,
    BOOLEAN * archiveExists)
{
    if (archiveExists == NULL)
    {
        return Common::ComUtility::OnPublicApiReturn(E_POINTER);
    }

    std::wstring dir;
    auto hr = Common::StringUtility::LpcwstrToWstring(appPackageRootDirectory, false, dir);
    if (FAILED(hr)) { return Common::ComUtility::OnPublicApiReturn(hr); }

    bool result = false;
    hr = Management::ImageStore::ImageStoreUtility::TryExtractApplicationPackage(
        dir, 
        WrapperFactory::create_rooted_com_proxy(const_cast<IFabricNativeImageStoreProgressEventHandler*>(progressHandler)),
        result).ToHResult();

    if (SUCCEEDED(hr))
    {
        *archiveExists = result ? TRUE : FALSE;
    }

    return Common::ComUtility::OnPublicApiReturn(hr);
}

HRESULT GenerateSfpkg(
    LPCWSTR appPackageRootDirectory,
    LPCWSTR destinationDirectory,
    BOOLEAN applyCompression,
    LPCWSTR sfPkgName,
    IFabricStringResult ** sfPkgFilePath)
{
    ErrorCode error(ErrorCodeValue::Success);

    std::wstring appPackageDir;
    error = Common::StringUtility::LpcwstrToWstring2(appPackageRootDirectory, false, appPackageDir);
    if (!error.IsSuccess()) { return Common::ComUtility::OnPublicApiReturn(move(error)); }

    std::wstring destDir;
    error = Common::StringUtility::LpcwstrToWstring2(destinationDirectory, false, destDir);
    if (!error.IsSuccess()) { return Common::ComUtility::OnPublicApiReturn(move(error)); }

    std::wstring sfPkg;
    error = Common::StringUtility::LpcwstrToWstring2(sfPkgName, true, sfPkg);
    if (!error.IsSuccess()) { return Common::ComUtility::OnPublicApiReturn(move(error)); }

    std::wstring result;
    error = Management::ImageStore::ImageStoreUtility::GenerateSfpkg(
        appPackageDir,
        destDir,
        (applyCompression == TRUE),
        sfPkg,
        result);
    if (!error.IsSuccess()) { return Common::ComUtility::OnPublicApiReturn(move(error)); }

    return ComStringResult::ReturnStringResult(result, sfPkgFilePath);
}

HRESULT ExpandSfpkg(
    LPCWSTR sfPkgFilePath,
    LPCWSTR appPackageRootDirectory)
{
    ErrorCode error(ErrorCodeValue::Success);

    std::wstring sfPkg;
    error = Common::StringUtility::LpcwstrToWstring2(sfPkgFilePath, false, sfPkg);
    if (!error.IsSuccess()) { return Common::ComUtility::OnPublicApiReturn(move(error)); }

    std::wstring destDir;
    error = Common::StringUtility::LpcwstrToWstring2(appPackageRootDirectory, false, destDir);
    if (!error.IsSuccess()) { return Common::ComUtility::OnPublicApiReturn(move(error)); }

    error = Management::ImageStore::ImageStoreUtility::ExpandSfpkg(
        sfPkg,
        destDir);
    return Common::ComUtility::OnPublicApiReturn(move(error));
}
